package userlogic

import (
	"context"

	"go-zero-admin/apps/system/cmd/rpc/internal/logic/userpost"
	"go-zero-admin/apps/system/cmd/rpc/internal/svc"
	"go-zero-admin/apps/system/cmd/rpc/syspb"
	"go-zero-admin/apps/system/model"
	"go-zero-admin/pkg/tool"
	"go-zero-admin/pkg/xerr"

	"github.com/duke-git/lancet/v2/convertor"
	"github.com/duke-git/lancet/v2/random"
	"github.com/duke-git/lancet/v2/validator"
	"github.com/jinzhu/copier"
	"github.com/pkg/errors"
	"github.com/zeromicro/go-zero/core/fx"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

type AddUserDataLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
	isExNameOrMobileOrEmailLogic *IsExNameOrMobileOrEmailLogic
	getUserPostListLogic         *userpostlogic.GetUserPostListLogic
}

func NewAddUserDataLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AddUserDataLogic {
	return &AddUserDataLogic{
		ctx:                          ctx,
		svcCtx:                       svcCtx,
		Logger:                       logx.WithContext(ctx),
		isExNameOrMobileOrEmailLogic: NewIsExNameOrMobileOrEmailLogic(ctx, svcCtx),
		getUserPostListLogic:         userpostlogic.NewGetUserPostListLogic(ctx, svcCtx),
	}
}

func (l *AddUserDataLogic) AddUserData(in *syspb.AddUserDataReq) (*syspb.AddUserDataResp, error) {
	user := in.GetParams()
	if user == nil || user.GetUserName() == "" || len(user.GetUserName()) < 6 || user.GetUserNickname() == "" ||
		user.GetMobile() == "" || !validator.IsChineseMobile(user.GetMobile()) ||
		user.GetUserEmail() == "" || !validator.IsEmail(user.GetUserEmail()) ||
		user.GetUserPassword() == "" || user.GetCreateUser() == "" || user.GetUpdateUser() == "" {
		return nil, errors.Wrapf(xerr.NewErrMsg("新增用户失败：参数缺失"),
			tool.GetErrMsgFormat("insert user"), "params is not existed", in)
	}
	if validator.IsWeakPassword(user.GetUserPassword()) {
		return nil, errors.Wrapf(xerr.NewErrMsg("弱密码（密码需包含字母、数字和特殊字符）"),
			tool.GetErrMsgFormat("insert user"), "password is week", in)
	}

	// 参数判断
	isExistResp, err := l.isExNameOrMobileOrEmailLogic.IsExNameOrMobileOrEmail(&syspb.IsExNameOrMobileOrEmailReq{
		UserName: user.GetUserName(),
		Mobile:   user.GetMobile(),
		Email:    user.GetUserEmail(),
	})
	if err != nil {
		return nil, err
	}
	if isExistResp.GetIsExist() {
		return nil, errors.Wrapf(xerr.NewErrMsg("新增用户："+user.GetUserName()+"' 失败，用户名称或手机号或邮箱已存在"),
			tool.GetErrMsgFormat("insert user"), "user name or mobile or email is existed", user)
	}

	// 保存
	if err = l.svcCtx.SysUserModel.Trans(l.ctx, func(context context.Context, session sqlx.Session) error {
		var data model.SysUser
		_ = copier.Copy(&data, user)

		data.UserSalt = random.RandString(10)
		data.UserPassword = tool.EncryptPassword(user.GetUserPassword(), user.GetUserSalt())

		r, e := l.svcCtx.SysUserModel.InsertEx(l.ctx, session, []*model.SysUser{&data})
		if e != nil {
			return e
		}
		id := r[0]

		// 设置用户所属角色信息
		e = l.HandleUserRole(in.GetRoleIds(), id, false, session)
		if e != nil {
			return e
		}

		// 设置用户岗位
		e = l.HandleUserPost(in.GetPostIds(), id, false, session)
		if e != nil {
			return e
		}

		return nil
	}); err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DbError),
			tool.GetErrMsgFormat("insert user"), err, in)
	}

	return &syspb.AddUserDataResp{}, nil
}

// HandleUserRole 处理用户角色关联信息
func (l *AddUserDataLogic) HandleUserRole(roleIds []int64, userId int64, isUp bool, session sqlx.Session) (err error) {
	enforcer := l.svcCtx.AdapterCasbin.SetCtxSession(l.ctx, session).Enforcer

	// 更新删除用户旧角色信息
	if isUp {
		if _, err = enforcer.RemoveFilteredGroupingPolicy(0, convertor.ToString(userId)); err != nil {
			return err
		}
	}

	// 新增用户角色关联
	if len(roleIds) > 0 {
		for _, v := range roleIds {
			_, err = enforcer.AddGroupingPolicy(convertor.ToString(userId), convertor.ToString(v))
			if err != nil {
				return err
			}
		}
	}

	return
}

// HandleUserPost 添加用户岗位信息
func (l *AddUserDataLogic) HandleUserPost(postIds []int64, userId int64, isUp bool, session sqlx.Session) error {
	// 更新删除用户旧岗位信息
	if isUp {
		// 查询出用户岗位信息
		userPostResp, err := l.getUserPostListLogic.GetUserPostList(&syspb.GetUserPostListReq{
			UserId: userId,
		})
		if err != nil {
			return err
		}
		list := userPostResp.GetList()

		// 如果用户岗位存在，则先删除
		if len(list) > 0 {
			var idList []int64
			fx.From(func(source chan<- interface{}) {
				for _, v := range list {
					source <- v
				}
			}).Map(func(item interface{}) interface{} {
				return item.(*syspb.SysUserPost).Id
			}).ForEach(func(item interface{}) {
				idList = append(idList, item.(int64))
			})
			err = l.svcCtx.SysUserPostModel.DeleteEx(l.ctx, session, idList, true, "")
			if err != nil {
				return err
			}
		}
	}

	// 保存岗位信息
	if len(postIds) > 0 {
		var userPostList []*model.SysUserPost
		fx.From(func(source chan<- interface{}) {
			for _, v := range postIds {
				source <- v
			}
		}).Map(func(item interface{}) interface{} {
			userPost := new(model.SysUserPost)
			userPost.UserId = userId
			userPost.PostId = item.(int64)
			userPost.CreateUser = convertor.ToString(userId)
			userPost.UpdateUser = convertor.ToString(userId)
			return userPost
		}).ForEach(func(item interface{}) {
			userPostList = append(userPostList, item.(*model.SysUserPost))
		})

		_, err := l.svcCtx.SysUserPostModel.InsertEx(l.ctx, session, userPostList)
		if err != nil {
			return err
		}
	}

	return nil
}
